package com.baitiaojun.video.handler;

import com.alibaba.fastjson.JSONObject;
import com.baitiaojun.api.domain.video.File;
import com.baitiaojun.api.domain.video.VideoBinaryPicture;
import com.baitiaojun.api.exception.ConditionException;
import com.baitiaojun.api.util.AESUtil;
import com.baitiaojun.api.util.ConstantUtil;
import com.baitiaojun.api.util.FileUtil;
import com.baitiaojun.api.util.SnowFlakeUtil;
import com.baitiaojun.video.mapper.FileMapper;
import com.baitiaojun.video.mapper.VideoBinaryPictureMapper;
import com.baitiaojun.video.support.FastDFSSupport;
import com.baitiaojun.video.support.PortraitSegmentationSupport;
import org.apache.commons.lang3.ObjectUtils;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.Java2DFrameConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @类名 BulletScreenMaskServiceImpl
 * @描述 TODO
 * @作者 白条君
 * @创建日期 2023/1/9 22:13
 * @版本 1.0
 */
@Service
public class BulletScreenMaskHandler {

    @Resource
    private FileMapper fileMapper;

    @Autowired
    private FastDFSSupport fastDFSSupport;

    //每隔16帧进行一次截取
    private static final int FIXED_RATE_FRAMES = 16;

    @Autowired
    private PortraitSegmentationSupport portraitSegmentationSupport;

    @Resource
    private VideoBinaryPictureMapper pictureMapper;

    public void videoConvertSilhouette(Long videoId, String md5) throws Exception {
        //根据md5获取File对象
        File file = fileMapper.getFileByMd5(md5);
        //获取group和filepath
        Map<String, String> filePathMap = FileUtil.splitFilePath(file.getUrl());
        String group = filePathMap.get("group");
        String filePath = filePathMap.get("filePath");
        //定义本地文件存放路径
        String localFileUrl = new StringBuilder(ConstantUtil.TEMP_FILE_DOWNLOAD_PATH)
                .append(videoId).append(".").append(file.getType()).toString();
        //文件下载
        fastDFSSupport.downLoadFile(group, filePath, localFileUrl);
        //视频帧截取
        FFmpegFrameGrabber fFmpegFrameGrabber = FFmpegFrameGrabber.createDefault(localFileUrl);
        fFmpegFrameGrabber.start();
        //总帧数
        int lengthFrames = fFmpegFrameGrabber.getLengthInFrames();
        //转换器，将帧转换成BufferedImage对象
        Java2DFrameConverter converter = new Java2DFrameConverter();
        int count = 1;
        //定义VideoBinaryPicture集合用于数据库添加
        List<VideoBinaryPicture> pictures = new ArrayList<>();
        //根据总帧数进行遍历
        for (int i = 0; i < lengthFrames; i++) {
            long timestamp = fFmpegFrameGrabber.getTimestamp();
            //获取一个视频帧
            Frame frame = fFmpegFrameGrabber.grabImage();
            //如果当前帧数是指定间隔获取的帧数就进行帧与黑白剪影的转换
            if (count == i) {
                if (ObjectUtils.isEmpty(frame)) {
                    throw new ConditionException("无效帧");
                }
                //帧添转换成bufferedImage，将bufferedImage写入到输出流，再将输出流转换成输入流
                BufferedImage bufferedImage = converter.getBufferedImage(frame);
                ByteArrayOutputStream ous = new ByteArrayOutputStream();
                ImageIO.write(bufferedImage, "png", ous);
                byte[] bytes = ous.toByteArray();
                InputStream ins = new ByteArrayInputStream(bytes);
                //生成黑白剪影
                java.io.File tempFile = java.io.File.createTempFile("convert-" + videoId + "-", ".png");
                BufferedImage grayImage = this.convertSilhouette(bufferedImage, ins);
                //写到createtempfile生成的临时文件
                ImageIO.write(grayImage, "png", tempFile);
                //上传视频剪影
                String fullUrl = fastDFSSupport.uploadCommonFile(tempFile, ConstantUtil.GROUP1, "png");
                //创建videobinarypicture对象添加到list集合
                VideoBinaryPicture picture = new VideoBinaryPicture();
                picture.setId(SnowFlakeUtil.getNextId());
                picture.setVideoid(videoId);
                picture.setFrameno(i);
                picture.setVideotimestamp(timestamp);
                picture.setUrl(fullUrl);
                picture.setCreatetime(new Date());
                pictures.add(picture);
                //count+帧间隔,作为下一次截取的帧数
                count += FIXED_RATE_FRAMES;
                boolean delete = tempFile.delete();
                if (!delete) {
                    throw new ConditionException("删除临时文件异常");
                }
            }
        }
        //将最开始下载下来的文件本身也删除
        java.io.File localFile = new java.io.File(localFileUrl);
        boolean delete = localFile.delete();
        if (!delete) {
            throw new ConditionException("删除临时下载文件异常");
        }
        //批量将videobinarypicture对象添加到数据库
        int res = pictureMapper.batchInsertBinaryPicture(pictures);
        if (res == 0) {
            throw new ConditionException("批量添加失败");
        }
    }

    public BufferedImage convertSilhouette(BufferedImage bufferedImage, InputStream ins) throws Exception {
        //获取人像分割的结果
        String res = portraitSegmentationSupport.bodySeg(ins);
        //结果转换成jsonobject
        JSONObject jsonObject = JSONObject.parseObject(res);
        if (ObjectUtils.isEmpty(jsonObject.get("labelmap"))) {
            throw new ConditionException((String) jsonObject.get("error_msg"));
        }
        //分割图转换成二值图
        return portraitSegmentationSupport
                .convert((String) jsonObject.get("labelmap"), bufferedImage.getWidth(), bufferedImage.getHeight());
    }
}
